/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Loader.h"
#include "DecompressorEmpty.h"
#include "DecompressorBmp.h"
#include "DecompressorPPM.h"
#include "DecompressorJpeg.h"
#include "DecompressorGif.h"
#include "DecompressorPng.h"
#include <vector>
#if  defined(WIN32)
#include "DecompressorWinPVR.h"
#endif
#if defined(IPHONE_VERSION) || defined(SAMSUNG_VERSION)
#include "DecompressorPVR.h"
#endif

#include "logs/Log.h"

namespace liba
{
namespace pictureformat
{

Loader::Loader(const filesystem::String & name)
	:	res_bmp( name + ".bmp" ),
		res_bmp_a( name + "_a.bmp" ),
		res_ppm( name + ".ppm" ),
		res_ppm_a( name + "_a.ppm" ),
		res_jpg( name + ".jpg" ),
		res_gif( name + ".gif" ),
		res_gif_a( name + "_a.gif" ),
		res_png( name + ".png" ),
#if defined(IPHONE_VERSION) || defined(SAMSUNG_VERSION) || defined(WIN32)
		res_pvr( name + ".pvr" ),
#endif
		decompressor( 0 ),
		decompressor_a( 0 ),
		name( name )
{}

Loader::~Loader()
{
	delete decompressor; decompressor=0;
	delete decompressor_a; decompressor_a=0;
}

bool Loader::is_ready()const
{
	if( decompressor )
		return true;
	if( 
		res_bmp.is_ready() &&
		res_bmp_a.is_ready() &&
		res_ppm.is_ready() &&
		res_ppm_a.is_ready() &&
		res_jpg.is_ready() &&
		res_gif.is_ready() &&
	    res_png.is_ready() &&
#if defined(IPHONE_VERSION) || defined(SAMSUNG_VERSION) || defined(WIN32)
		res_pvr.is_ready() &&
#endif
		res_gif_a.is_ready() )
	{
		if( res_bmp.get_size() )
			decompressor = new DecompressorBmp( res_bmp.get_data(), res_bmp.get_size() );
		else if( res_ppm.get_size() )
			decompressor = new DecompressorPPM( res_ppm.get_data(), res_ppm.get_size() );
		else if( res_jpg.get_size() )
			decompressor = new DecompressorJpeg( res_jpg.get_data(), res_jpg.get_size() );
		else if( res_gif.get_size() )
			decompressor = new DecompressorGif( res_gif.get_data(), res_gif.get_size() );
		else if( res_png.get_size() )
			decompressor = new DecompressorPng( res_png.get_data(), res_png.get_size() );
#if defined(IPHONE_VERSION) || defined(SAMSUNG_VERSION) || defined(WIN32)
		else if( res_pvr.get_size() )
			decompressor = new DecompressorPVR( res_pvr.get_data(), res_pvr.get_size() );
#endif
		else
			decompressor = new DecompressorEmpty();

		if( res_bmp_a.get_size() )
			decompressor_a = new DecompressorBmp( res_bmp_a.get_data(), res_bmp_a.get_size() );
		else if( res_ppm_a.get_size() )
			decompressor_a = new DecompressorPPM( res_ppm_a.get_data(), res_ppm_a.get_size() );
		else if( res_gif_a.get_size() )
			decompressor_a = new DecompressorGif( res_gif_a.get_data(), res_gif_a.get_size() );
		else
			decompressor_a = 0;

		if( decompressor_a )
		{
			bool dimensions_match = true;
			if( decompressor->get_frame_count() != decompressor_a->get_frame_count() )
				dimensions_match = false;
			else
			{
				for( int m = 0; m != decompressor->get_frame_count(); ++m )
					if( decompressor->get_width(m) != decompressor_a->get_width(m) ||
						decompressor->get_height(m) != decompressor_a->get_height(m) )
					{
						dimensions_match = false;
					}
			}

			if( !dimensions_match )
			{
				delete decompressor_a; decompressor_a = 0;
				logs::log() << logs::warning << "In Loader::is_ready() decompressor_a and decompressor properties do not match: {" << name << "}\n";
			}
		}
		return true;
	}
	return false;
}

int Loader::get_width(int frame)const
{
	return decompressor->get_width(frame);
}

int Loader::get_height(int frame)const
{
	return decompressor->get_height(frame);
}

int Loader::get_frame_count()const
{
	return decompressor->get_frame_count();
}

bool Loader::is_valid()const
{
	return get_frame_count() > 0;
}

Format Loader::get_best_format()const
{
	if( decompressor_a )
		return A8R8G8B8;
	return decompressor->get_best_format();
}

void Loader::reset(Format f, int frame)
{
	this->frame = frame;
	if( decompressor_a )
	{
		decompressor->reset( A8R8G8B8, frame );
		decompressor_a->reset( R8G8B8, frame );
		twin_format = f;
	}
	else
	{
		decompressor->reset( f, frame );
	}
}

void Loader::unpack_scanline(void * dst)
{
	if( decompressor_a )
	{
		std::vector<char> colors;
		std::vector<char> alphas;
		colors.reserve(4*get_width(frame));
		alphas.reserve(3*get_width(frame));
		decompressor->unpack_scanline( &(colors.front()) );
		decompressor_a->unpack_scanline( &(alphas.front()) );
		char * cp = &(colors.front()) + 3;
		const char * ap = &(alphas.front());
		for( int x = 0; x < get_width(frame); ++x, cp += 4, ap += 3 )
			*cp = *ap;
		convert_scanline<A8R8G8B8>(twin_format, &(colors.front()), dst, get_width(frame));
	}
	else
	{
		decompressor->unpack_scanline( dst );
	}
}

void Loader::skip_scanline(int count)
{
	decompressor->skip_scanline(count);
	if( decompressor_a )
		decompressor_a->skip_scanline(count);
}

} // namespace pictureformat
} // namespace liba

